
use sysinfo::*;
use tauri::Manager;
use window_vibrancy::apply_mica;

use std::process::Command;
use std::str;
use serde::Serialize;

#[derive(Serialize)]
struct CustomError {
    message: String,
    code: u32,
}

#[tauri::command]
fn greet(name: &str) -> String {
    format!("fuck you , {}! You've been greeted from Rust!", name)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .setup(|app| {
            let window = app.get_webview_window("main").unwrap();

            #[cfg(target_os = "macos")]
            apply_vibrancy(&window, NSVisualEffectMaterial::HudWindow, None, None)
                .expect("Unsupported platform! 'apply_vibrancy' is only supported on macOS");

            #[cfg(target_os = "windows")]
            apply_mica(&window, Some(true))
                .expect("Unsupported platform! 'apply_blur' is only supported on Windows");
            Ok(())
        })
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![
            get_process_pids ,
          get_windows_process_names, open_specific_process_directory ,kill_specific_process ,
            get_process_cpu_usage, get_process_memory_usage , get_process_path])

        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}


  fn get_windows_process_pids() -> Vec<u32> {
    let mut sys = System::new_all();
    sys.refresh_all(); // 刷新系统信息

    let processes_info = sys.processes();

    let mut process_list = Vec::new();

    for (pid, process) in processes_info.iter() {
        process_list.push(pid.as_u32());
    }
    process_list
}

#[tauri::command]
  fn get_process_pids() -> Vec<u32>  {
    let mut sys = System::new_all();
    sys.refresh_all(); // 刷新系统信息

    let processes_info = sys.processes();

    let mut process_list = Vec::new();

    for (pid, process) in processes_info.iter() {
        process_list.push(pid.as_u32());
    }
    process_list
}



#[tauri::command]
  fn get_windows_process_names(pids: Vec<u32>) ->Vec<String>{
    let mut sys = System::new_all();
    let mut process_list = Vec::new();
    for pid in pids {
        if let Some(process) = sys.process(Pid::from(pid as usize)) {
            let process_name = process.name().to_str().unwrap().to_string();
            process_list.push(process_name);
        }
    }
    process_list
}

pub fn get_process_directory() -> Vec<String>  {
    let mut sys = System::new_all();
    sys.refresh_all();

    let processes_info = sys.processes();

    let mut process_list = Vec::new();
    for (pid, process) in processes_info.iter() {
        process_list.push(
            process
                .cmd()
                .iter()
                .filter_map(|os_str| os_str.to_str().map(String::from))
                .collect(),
        );
    }
    process_list
}

pub fn get_process_status() -> Vec<String> {
    let mut sys = System::new_all();
    sys.refresh_all();

    let processes_info = sys.processes();

    let mut process_list = Vec::new();

    for (pid, process) in processes_info.iter() {
        process_list.push(process.status().to_string());
    }
    process_list
}
#[tauri::command]
fn get_process_cpu_usage(pids: Vec<u32>) -> Vec<f32> {
    let mut sys = System::new_all();
    let mut process_list = Vec::new();

    std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
    sys.refresh_processes_specifics(
        ProcessesToUpdate::All,
        true,
        ProcessRefreshKind::nothing().with_cpu(),
    );
    for pid in pids {
        if let Some(process) = sys.process(Pid::from(pid.clone() as usize)) {
            let cpu_usage = process.cpu_usage() / sys.cpus().len() as f32;
            process_list.push(cpu_usage);
        }
    }
    process_list
}
#[tauri::command]
  fn get_process_memory_usage(pids: Vec<u32>) -> Vec<f32>  {
    let mut mem_list = Vec::new();

    let sys = System::new_all();
    for pid in pids {
        if let Some(process) = sys.process(Pid::from(pid as usize)) {
            let mem_usage = process.memory();
            let men_rate = mem_usage as f32 / sys.total_memory() as f32;
            mem_list.push(men_rate * 100f32);
        }
    }
    mem_list
}
#[derive(Debug)]
struct ProcessGpuUsage {
    pid: u32,
    gpu_usage: f32,
    memory_used: f32,
}


pub fn get_process_disk_usage() -> Vec<f32>  {
    let mut disk_list = Vec::new();

    let sys = System::new_all();
    let pids = get_windows_process_pids() ;
    for pid in pids {
        if let Some(process) = sys.process(Pid::from(pid as usize)) {
            let disk = process.disk_usage();
            let read_byte = disk.read_bytes;
            let write_byte = disk.written_bytes;
            let disk_rate = (read_byte + write_byte) as f32
                / ((disk.total_read_bytes + disk.total_written_bytes) as f32);
            disk_list.push(disk_rate);
        }
    }
    disk_list
}


#[tauri::command]
fn get_process_path(pids: Vec<u32>) -> Vec<String> {
    let mut sys = System::new_all();

    let mut paths = Vec::new();
    for pid in pids {
        if let Some(process) = sys.process(Pid::from(pid as usize)) {
            let path_buf = process.exe();
            match path_buf {
                Some(path) => {
                    paths.push(path.to_str().unwrap().to_string());
                }
                None => {
                    paths.push("".to_string());
                }
            }
        }
    }
    paths
}


use std::ffi::OsString;


pub fn get_process_path_by_winapi(pids: &Vec<u32>) -> Result<OsString, String> {
    use std::os::windows::ffi::OsStringExt;
    use std::ptr::null_mut;
    use winapi::um::handleapi::CloseHandle;
    use winapi::um::processthreadsapi::OpenProcess;
    use winapi::um::psapi::GetModuleFileNameExW;
    use winapi::um::winnt::PROCESS_QUERY_INFORMATION ;
    use winapi::um::winnt::PROCESS_VM_READ ;
    use winapi::um::winnt::HANDLE;
    let mut paths = OsString::new();
    for pid in pids {
        unsafe {
            // 打开进程
            let handle: HANDLE = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, *pid);
            if handle.is_null() {
                return Err("Failed to open process".to_string());
            }

            // 获取进程路径
            let mut buffer = [0u16; 1024];
            let len = GetModuleFileNameExW(handle, null_mut(), buffer.as_mut_ptr(), buffer.len() as u32);
            if len == 0 {
                CloseHandle(handle);
                return Err("Failed to get process path".to_string());
            }

            // 关闭句柄
            CloseHandle(handle);

            // 将 UTF-16 转换为 OsString
            let path = OsString::from_wide(&buffer[..len as usize]);
            if !path.is_empty() {
                 paths.push(path);
            }else {
                paths.push(OsString::from(""));
            }
        }
    }
    Ok(paths)

}


pub fn get_process_description(bin_paths: &Vec<String>) -> Result<Vec<String>,  anyhow::Error> {
    use windows::{
        core::PCWSTR,
        Win32::Storage::FileSystem::GetFileVersionInfoSizeW,
        Win32::Storage::FileSystem::GetFileVersionInfoW,
        Win32::Storage::FileSystem::VerQueryValueW,
        Win32::Foundation::GetLastError,
    };
    let mut descriptions = Vec::new();


    for   bin_path in bin_paths {
        if bin_path.is_empty() {
            descriptions.push("".to_string());
            continue;
        }
        let  bin_path =bin_path.encode_utf16() // 将字符串编码为 UTF-16
            .chain(std::iter::once(0)) // 添加 null 终止符
            .collect::<Vec<u16>>(); // 转换为 Vec<u16>
        // 获取版本信息的大小
        let info_size = unsafe { GetFileVersionInfoSizeW(PCWSTR(bin_path.as_ptr()), None) };
        if info_size == 0 {
            eprintln!("Failed to get version info size: {:?}", unsafe { GetLastError() });
        }

        // 分配缓冲区并获取版本信息
        let mut buffer = vec![0u8; info_size as usize];

        // 查询语言和代码页
        let mut lang_codepage_ptr = std::ptr::null_mut();
        let mut lang_codepage_size = 0;
        let translation_query = "\\VarFileInfo\\Translation"
            .encode_utf16()
            .chain(std::iter::once(0))
            .collect::<Vec<u16>>();


        // 解析语言和代码页
        let lang_codepage = unsafe { std::slice::from_raw_parts(lang_codepage_ptr as *const u16, lang_codepage_size as usize / 2) };
        let lang = lang_codepage[0];
        let codepage = lang_codepage[1];

        // 查询文件描述信息
        let description_query = format!("\\StringFileInfo\\{:04x}{:04x}\\FileDescription", lang, codepage)
            .encode_utf16()
            .chain(std::iter::once(0))
            .collect::<Vec<u16>>();

        let mut description_ptr = std::ptr::null_mut();
        let mut description_size = 0;

        if unsafe {
            VerQueryValueW(
                buffer.as_ptr() as _,
                PCWSTR(description_query.as_ptr()),
                &mut description_ptr,
                &mut description_size,
            )
        } == false
        {
            eprintln!("Failed to query file description: {:?}", unsafe { GetLastError() });
            return Err(windows::core::Error::from_win32().into());
        }

        // 解析文件描述信息
        let description = unsafe { std::slice::from_raw_parts(description_ptr as *const u16, description_size as usize / 2) };
        let description_str = String::from_utf16_lossy(description);

        println!("File Description: {}", description_str);
        descriptions.push(description_str);
    }

    Ok(descriptions)
}


#[tauri::command]
fn  kill_specific_process(pid: u32)  {
    let mut sys = System::new_all();
    if let Some(process) = sys.process(Pid::from(pid as usize)) {
        process.kill();
    }
}



#[tauri::command]
fn open_specific_process_directory(path: String) {
    let dir = std::path::Path::new(&path).parent().unwrap();
    println!("{:?}", dir);
    Command::new("explorer.exe").arg(dir).spawn().unwrap();
}